home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / ANSI / c-client / os_dpc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  12.5 KB  |  476 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- MS-DOS (PC/TCP) version
  3.  *
  4.  * Author:    Mark Crispin/Ken Bobey
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    11 April 1989
  13.  * Last Edited:    15 June 1993
  14.  *
  15.  * Copyright 1993 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36. /* TCP input buffer -- must be large enough to prevent overflow */
  37.  
  38. #define BUFLEN 8192
  39.  
  40.  
  41. /* TCP I/O stream (must be before osdep.h is included) */
  42.  
  43. #define TCPSTREAM struct tcp_stream
  44. TCPSTREAM {
  45.   char *host;            /* host name */
  46.   char *localhost;        /* local host name */
  47.   int tcps;            /* tcp socket */
  48.   long ictr;            /* input counter */
  49.   char *iptr;            /* input pointer */
  50.   char ibuf[BUFLEN];        /* input buffer */
  51. };
  52.  
  53.  
  54. /* Private function prototypes */
  55.  
  56. #include "mail.h"
  57. #include "osdep.h"
  58. #include <time.h>
  59. #include <sys\timeb.h>
  60. #include <4bsddefs.h>
  61. #include <sys\socket.h>
  62. #include <errno.h>
  63. #include <netinet\in.h>
  64. #include <netdb.h>
  65. #include "misc.h"
  66.  
  67.  
  68. /* Global data */
  69.  
  70. unsigned long rndm = 0xfeed;    /* initial `random' number */
  71.  
  72. /* Write current time in RFC 822 format
  73.  * Accepts: destination string
  74.  */
  75.  
  76. char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  77.  
  78. void rfc822_date (char *date)
  79. {
  80.   time_t ti = time (0);
  81.   struct tm *t;
  82.   tzset ();            /* initialize timezone stuff */
  83.   t = localtime (&ti);        /* output local time */
  84.   sprintf (date,"%s, %d %s %d %02d:%02d:%02d %s",
  85.        days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  86.        t->tm_hour,t->tm_min,t->tm_sec,tzname[t->tm_isdst]);
  87. }
  88.  
  89. /* Get a block of free storage
  90.  * Accepts: size of desired block
  91.  * Returns: free storage block
  92.  */
  93.  
  94. void *fs_get (size_t size)
  95. {
  96.   void *block = malloc (size);
  97.   if (!block) fatal ("Out of free storage");
  98.   return (block);
  99. }
  100.  
  101.  
  102. /* Resize a block of free storage
  103.  * Accepts: ** pointer to current block
  104.  *        new size
  105.  */
  106.  
  107. void fs_resize (void **block,size_t size)
  108. {
  109.   if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
  110. }
  111.  
  112.  
  113. /* Return a block of free storage
  114.  * Accepts: ** pointer to free storage block
  115.  */
  116.  
  117. void fs_give (void **block)
  118. {
  119.   free (*block);
  120.   *block = NIL;
  121. }
  122.  
  123.  
  124. /* Report a fatal error
  125.  * Accepts: string to output
  126.  */
  127.  
  128. void fatal (char *string)
  129. {
  130.   mm_fatal (string);        /* pass the string */
  131.   abort ();            /* die horribly */
  132. }
  133.  
  134. /* Copy string with CRLF newlines
  135.  * Accepts: destination string
  136.  *        pointer to size of destination string
  137.  *        source string
  138.  *        length of source string
  139.  */
  140.  
  141. char *strcrlfcpy (char **dst,unsigned long *dstl,char *src,unsigned long srcl)
  142. {
  143.   if (srcl > *dstl) {        /* resize if not enough space */
  144.     fs_give ((void **) dst);    /* fs_resize does an unnecessary copy */
  145.     *dst = (char *) fs_get ((*dstl = srcl) + 1);
  146.   }
  147.                 /* copy strings */
  148.   if (srcl) memcpy (*dst,src,srcl);
  149.   *(*dst + srcl) = '\0';    /* tie off destination */
  150.   return *dst;            /* return destination */
  151. }
  152.  
  153.  
  154. /* Length of string after strcrlfcpy applied
  155.  * Accepts: source string
  156.  *        length of source string
  157.  */
  158.  
  159. unsigned long strcrlflen (STRING *s)
  160. {
  161.   return SIZE (s);        /* no-brainer on DOS! */
  162. }
  163.  
  164.  
  165. /* Return my home directory name
  166.  * Returns: my home directory name
  167.  */
  168.  
  169. char *hdname = NIL;
  170.  
  171. char *myhomedir ()
  172. {
  173.   int i;
  174.   char *s;
  175.   if (!hdname) {        /* get home directory name if not yet known */
  176.     hdname = cpystr ((s = getenv ("HOME")) ? s : "");
  177.     if ((i = strlen (hdname)) && ((hdname[i-1] == '\\') || (hdname[i-1]=='/')))
  178.       hdname[i-1] = '\0';    /* tie off trailing directory delimiter */
  179.   }
  180.   return hdname;
  181. }
  182.  
  183. /* TCP/IP open
  184.  * Accepts: host name
  185.  *        contact port number
  186.  * Returns: TCP/IP stream if success else NIL
  187.  */
  188.  
  189. TCPSTREAM *tcp_open (char *host,long port)
  190. {
  191.   TCPSTREAM *stream = NIL;
  192.   struct sockaddr_in sin;
  193.   struct hostent *host_name;
  194.   int sock;
  195.   long adr,i,j,k,l;
  196.   char *s;
  197.   char tmp[MAILTMPLEN];
  198.   char *hostname = cpystr (host);
  199.                 /* set default gets routine */
  200.   if (!mailgets) mailgets = mm_gets;
  201.   /* The domain literal form is used (rather than simply the dotted decimal
  202.      as with other Unix programs) because it has to be a valid "host name"
  203.      in mailsystem terminology. */
  204.   sin.sin_family = AF_INET;    /* family is always Internet */
  205.                 /* look like domain literal? */
  206.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  207.     strcpy (tmp,host+1);    /* yes, copy number part */
  208.     tmp[strlen (tmp)-1] = '\0';
  209.     if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
  210.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  211.       mm_log (tmp,ERROR);
  212.       fs_give ((void **) hostname);
  213.       return NIL;
  214.     }
  215.   }
  216.   else {            /* lookup host name */
  217.     if ((host_name = gethostbyname (lcase (hostname)))) {
  218.                 /* copy host name */
  219.       strcpy (hostname,host_name->h_name);
  220.                 /* copy host addresses */
  221.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  222.     }
  223.     else {
  224.       sprintf (tmp,"Host not found: %s",host);
  225.       mm_log (tmp,ERROR);
  226.       fs_give ((void **) hostname);
  227.       return NIL;
  228.     }
  229.   }
  230.  
  231.                 /* copy port number in network format */
  232.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  233.                 /* get a TCP stream */
  234.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
  235.     sprintf (tmp,"Unable to create TCP socket (%d)",errno);
  236.     mm_log (tmp,ERROR);
  237.     fs_give ((void **) hostname);
  238.     return NIL;
  239.   }
  240.                 /* open connection */
  241.   if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
  242.     switch (errno) {        /* analyze error */
  243.     case ECONNREFUSED: s = "Refused"; break;
  244.     case ENOBUFS: s = "Insufficient system resources"; break;
  245.     case ETIMEDOUT: s = "Timed out"; break;
  246.     default: s = "Unknown error"; break;
  247.     }
  248.     sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hostname,port,s,errno);
  249.     mm_log (tmp,ERROR);
  250.     fs_give ((void **) hostname);
  251.     close (sock);
  252.     return NIL;
  253.   }
  254.                 /* create TCP/IP stream */
  255.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  256.   stream->host = hostname;    /* official host name */
  257.   if (adr = gethostid ()) {    /* get local IP address */
  258.     i = adr >> 24; j = (adr >> 16) & 0xff; k = (adr >> 8) & 0xff;
  259.     l = adr & 0xff;
  260.     sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  261.     stream->localhost = cpystr (tmp);
  262.   }
  263.   else stream->localhost = cpystr ("random-pc");
  264.   stream->tcps = sock;        /* init socket */
  265.   stream->ictr = 0;        /* init input counter */
  266.   return stream;        /* return success */
  267. }
  268.   
  269. /* TCP/IP authenticated open
  270.  * Accepts: host name
  271.  *        service name
  272.  * Returns: TCP/IP stream if success else NIL
  273.  */
  274.  
  275. TCPSTREAM *tcp_aopen (char *host,char *service)
  276. {
  277.   return NIL;            /* always NIL on DOS */
  278. }
  279.  
  280. /* TCP/IP receive line
  281.  * Accepts: TCP/IP stream
  282.  * Returns: text line string or NIL if failure
  283.  */
  284.  
  285. char *tcp_getline (TCPSTREAM *stream)
  286. {
  287.   int n,m;
  288.   char *st,*ret,*stp;
  289.   char c = '\0';
  290.   char d;
  291.                 /* make sure have data */
  292.   if (!tcp_getdata (stream)) return NIL;
  293.   st = stream->iptr;        /* save start of string */
  294.   n = 0;            /* init string count */
  295.   while (stream->ictr--) {    /* look for end of line */
  296.     d = *stream->iptr++;    /* slurp another character */
  297.     if ((c == '\015') && (d == '\012')) {
  298.       ret = (char *) fs_get (n--);
  299.       memcpy (ret,st,n);    /* copy into a free storage string */
  300.       ret[n] = '\0';        /* tie off string with null */
  301.       return ret;
  302.     }
  303.     n++;            /* count another character searched */
  304.     c = d;            /* remember previous character */
  305.   }
  306.                 /* copy partial string from buffer */
  307.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  308.                 /* get more data from the net */
  309.   if (!tcp_getdata (stream)) return NIL;
  310.                 /* special case of newline broken by buffer */
  311.   if ((c == '\015') && (*stream->iptr == '\012')) {
  312.     stream->iptr++;        /* eat the line feed */
  313.     stream->ictr--;
  314.     ret[n - 1] = '\0';        /* tie off string with null */
  315.   }
  316.                 /* else recurse to get remainder */
  317.   else if (st = tcp_getline (stream)) {
  318.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  319.     memcpy (ret,stp,n);        /* copy first part */
  320.     memcpy (ret + n,st,m);    /* and second part */
  321.     fs_give ((void **) &stp);    /* flush first part */
  322.     fs_give ((void **) &st);    /* flush second part */
  323.     ret[n + m] = '\0';        /* tie off string with null */
  324.   }
  325.   return ret;
  326. }
  327.  
  328. /* TCP/IP receive buffer
  329.  * Accepts: TCP/IP stream
  330.  *        size in bytes
  331.  *        buffer to read into
  332.  * Returns: T if success, NIL otherwise
  333.  */
  334.  
  335. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  336. {
  337.   unsigned long n;
  338.   char *bufptr = buffer;
  339.   while (size > 0) {        /* until request satisfied */
  340.     if (!tcp_getdata (stream)) return NIL;
  341.     n = min (size,stream->ictr);/* number of bytes to transfer */
  342.                 /* do the copy */
  343.     memcpy (bufptr,stream->iptr,n);
  344.     bufptr += n;        /* update pointer */
  345.     stream->iptr +=n;
  346.     size -= n;            /* update # of bytes to do */
  347.     stream->ictr -=n;
  348.   }
  349.   bufptr[0] = '\0';        /* tie off string */
  350.   return T;
  351. }
  352.  
  353.  
  354. /* TCP/IP receive data
  355.  * Accepts: TCP/IP stream
  356.  * Returns: T if success, NIL otherwise
  357.  */
  358.  
  359. long tcp_getdata (TCPSTREAM *stream)
  360. {
  361.   fd_set fds;
  362.   FD_ZERO (&fds);        /* initialize selection vector */
  363.   if (stream->tcps < 0) return NIL;
  364.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  365.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  366.                 /* block and read */
  367.     if ((select (stream->tcps+1,&fds,0,0,0) < 0) ||
  368.     ((stream->ictr = read (stream->tcps,stream->ibuf,BUFLEN)) < 1)) {
  369.       close (stream->tcps);    /* nuke the socket */
  370.       stream->tcps = -1;
  371.       return NIL;
  372.     }
  373.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  374.   }
  375.   return T;
  376. }
  377.  
  378. /* TCP/IP send string as record
  379.  * Accepts: TCP/IP stream
  380.  *        string pointer
  381.  * Returns: T if success else NIL
  382.  */
  383.  
  384. long tcp_soutr (TCPSTREAM *stream,char *string)
  385. {
  386.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  387. }
  388.  
  389.  
  390. /* TCP/IP send string
  391.  * Accepts: TCP/IP stream
  392.  *        string pointer
  393.  *        byte count
  394.  * Returns: T if success else NIL
  395.  */
  396.  
  397. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  398. {
  399.   long i;
  400.   fd_set fds;
  401.   FD_ZERO (&fds);        /* initialize selection vector */
  402.   if (stream->tcps < 0) return NIL;
  403.   while (size > 0) {        /* until request satisfied */
  404.     FD_SET (stream->tcps,&fds);/* set bit in selection vector */
  405.     if ((select (stream->tcps+1,0,&fds,0,0) < 0) ||
  406.     ((i = write (stream->tcps,string,size)) < 0)) {
  407.       close (stream->tcps);    /* nuke the socket */
  408.       stream->tcps = -1;
  409.       return NIL;
  410.     }
  411.     size -= i;            /* count this size */
  412.     string += i;
  413.   }
  414.   return T;            /* all done */
  415. }
  416.  
  417.  
  418. /* TCP/IP close
  419.  * Accepts: TCP/IP stream
  420.  */
  421.  
  422. void tcp_close (TCPSTREAM *stream)
  423. {
  424.                 /* nuke the socket */
  425.   if (stream->tcps >= 0) close (stream->tcps);
  426.   stream->tcps = -1;
  427.                 /* flush host names */
  428.   fs_give ((void **) &stream->host);
  429.   fs_give ((void **) &stream->localhost);
  430.   fs_give ((void **) &stream);    /* flush the stream */
  431. }
  432.  
  433. /* TCP/IP get host name
  434.  * Accepts: TCP/IP stream
  435.  * Returns: host name for this stream
  436.  */
  437.  
  438. char *tcp_host (TCPSTREAM *stream)
  439. {
  440.   return stream->host;        /* return host name */
  441. }
  442.  
  443.  
  444. /* TCP/IP get local host name
  445.  * Accepts: TCP/IP stream
  446.  * Returns: local host name
  447.  */
  448.  
  449. char *tcp_localhost (TCPSTREAM *stream)
  450. {
  451.   return stream->localhost;    /* return local host name */
  452. }
  453.  
  454. /* These functions are only used by rfc822.c for calculating cookies.  So this
  455.  * is good enough.  If anything better is needed fancier functions will be
  456.  * needed.
  457.  */
  458.  
  459.  
  460. /* Return random number
  461.  */
  462.  
  463. long random ()
  464. {
  465.   return rndm *= 0xdae0;
  466. }
  467.  
  468.  
  469. /* Return `process ID'
  470.  */
  471.  
  472. long getpid ()
  473. {
  474.   return 1;
  475. }
  476.